"""ase"""
import inspect
import logging as log
import re
from functools import wraps
from http.cookiejar import CookieJar
from requests import Session


REQUEST_PARAMS_NAME = list(inspect.signature(Session.request).parameters.keys())[1:]


def get_json_response(response):
    """获取响应"""
    response.raise_for_status()
    return response.json()


def get_response(response):
    """直接返回原始响应体，由业务端自行处理"""
    response.raise_for_status()
    return response


class BaseClient:
    """服务系统client集合基类"""
    DOMAIN = ''
    VERIFY = False
    PROXIES = None

    def __init__(self):
        self.session = self.__init_session()

    def __init_session(self) -> Session:
        session = Session()
        session.verify = self.VERIFY
        session.proxies = self.PROXIES
        session.cookies = self.get_cookies()
        session.headers = self.get_headers()
        return session

    def get_cookies(self):
        """获取cookies，继承时修改该方法用于cookies认证"""
        return CookieJar()

    def get_headers(self):
        """获取headers，继承时修改该方法用于cookies认证"""
        return {}


def api(method, route, res_callback=get_json_response):
    """
    标记Client类方法为调用api接口方法

    method： request请求方法
    route： 请求url，包含路由参数直接使用关键字format格式拼接，比如： /xxx/{pk}/xxx
    res_callback: 指定响应response解析方法
    """

    def decorate(func):

        @wraps(func)
        def wrapper(self, *args, **kwargs):
            """
            请求发送逻辑

            函数需要定义发送请求的Session.request参数和发送请求的路由参数
            为防止路由参数和Session.request参数冲突，路由参数请不要使用json/headers等request参数
            """
            params = inspect.signature(func).bind(self, *args, **kwargs)
            params.apply_defaults()
            func_params = params.arguments
            request_params = {i: func_params.pop(i) for i in REQUEST_PARAMS_NAME if i in func_params}
            route_params = re.findall('{([^{}]+)}', route)
            url = f'{self.DOMAIN}{route.format(**{i: func_params.pop(i) for i in route_params})}'
            log.info('request api[%s]', url)
            response = self.session.request(method=method, url=url, **request_params)
            return res_callback(response)

        return wrapper

    return decorate
